use std::convert::From;

pub const FIGERPRINT_SIZE: usize = 1;
pub const BUCKET_SIZE: usize = 4;
const EMPTY_FINGERPRINT_DATA: [u8; FIGERPRINT_SIZE] = [100; FIGERPRINT_SIZE];

//指纹定义
#[derive(Debug, PartialEq, Copy, Clone, Hash)]
pub struct FingerPrint {
   pub data: [u8; FIGERPRINT_SIZE], 
}

//指纹
impl FingerPrint {
    //转换函数,从&[u8; N] -> FingerPrint
    pub fn from_data(data: &[u8; FIGERPRINT_SIZE]) -> Option<Self> {
        let res = Self { data: *data };
        if res.is_empty() {
            None
        } else {
            Some(res)
        }
    }

    pub fn empty() -> Self {
        Self { data: EMPTY_FINGERPRINT_DATA,}
    }

    pub fn is_empty(&self) -> bool {
         self.data == EMPTY_FINGERPRINT_DATA
    }
    /// Sets the fingerprint value to a previously exported one via in-memory copy.
    fn slice_copy(&mut self, fingerprint: &[u8]){
        self.data.copy_from_slice(fingerprint);
    } 
}
//桶
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Bucket {
   pub buffer: [FingerPrint; BUCKET_SIZE],
}
impl Bucket {
   pub fn new() -> Self {
        Self { buffer: [FingerPrint::empty(); BUCKET_SIZE]}
    }

    pub fn insert(&mut self, fp: FingerPrint) -> bool {
        for bfp in &mut self.buffer {
            if bfp.is_empty() {
                *bfp = fp;
                return true;
            }
        }
        false
    }
    pub fn delete(&mut self, fp: FingerPrint) -> bool {
        match self.get_fp_index(fp) {
            Some(index) => {
               let _ = self.buffer[index] == FingerPrint::empty();
               true
            }
            None => false,
        }
    }
    //获取指纹索引下标
   pub fn get_fp_index(&self, fp: FingerPrint) -> Option<usize> {
        self.buffer.iter().position(|i| *i == fp)
    }
    //Returns all current fingerprint data of the current buffer for storage.
    pub fn get_fp_data(&self) -> Vec<u8> {
        self.buffer
            .iter()
            .flat_map(|f| f.data.iter())
            .cloned()
            .collect()
    }
}
impl From<&[u8]> for Bucket {
    ///Constructs a buffer of fingerprints from a set of previously exported fingerprint.
    fn from (fingerprints: &[u8]) -> Self {
        let mut buffer = [FingerPrint::empty(); BUCKET_SIZE];
        for (idx, value) in fingerprints.chunks(FIGERPRINT_SIZE).enumerate(){
            buffer[idx].slice_copy(value);
        }
        Bucket { buffer}
    }
}
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_fp_is_empty(){
        let fp = FingerPrint::empty();
        assert_eq!(fp.is_empty(),true );
    }
    #[test]
    fn test_fp_from_data() {
        let valid_fp: [u8; FIGERPRINT_SIZE] = [0; FIGERPRINT_SIZE];
        let fp = FingerPrint::from_data(&valid_fp);
        let fp1 = FingerPrint{
            data:[0; FIGERPRINT_SIZE],
        };
        assert_eq!(fp,Some(fp1));
    }
    #[test]
    fn test_bk_new() {
        let bk = Bucket::new();
        let fp = FingerPrint::empty();
        assert_eq!(Some(bk.buffer[0]),Some(fp));
    }
    #[test]
    fn test_bk_insert_delete() {
        let mut bk = Bucket::new();
        let fp = FingerPrint::empty();
        let bk_in = bk.insert(fp);
        let bk_del = bk.delete(fp);
        assert_eq!(bk_in, true );
        assert_eq!(bk_del, true );
    }
}
